#include <cmath>

#include <QtOpenGL/QGLWidget>

#include "Utils.h"

static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;

void solidCylinder(double radius, double height, int slices, int stacks)
{
    int i,j;
    double z0,z1;
    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );

    glBegin(GL_TRIANGLE_FAN);
	glNormal3d(0.0, 0.0, -1.0 );
	glVertex3d(0.0, 0.0,  0.0 );
	for (j=0; j<=slices; j++)
	  glVertex3d(cos(TwoPi / slices * j)*radius, sin(TwoPi / slices * j)*radius, 0.0);
    glEnd();

    glBegin(GL_TRIANGLE_FAN);
	glNormal3d(0.0, 0.0, 1.0   );
	glVertex3d(0.0, 0.0, height);
	for (j=slices; j>=0; j--)
	  glVertex3d(cos(TwoPi / slices * j)*radius, sin(TwoPi / slices * j)*radius, height);
    glEnd();

    z0 = 0.0;
    z1 = zStep;

    for (i=1; i<=stacks; i++)
    {
	if (i==stacks)
	    z1 = height;

	glBegin(GL_QUAD_STRIP);
	    for (j=0; j<=slices; j++ )
	    {
		glNormal3d(cos(TwoPi / slices * j),        sin(TwoPi / slices * j),        0.0 );
		glVertex3d(cos(TwoPi / slices * j)*radius, sin(TwoPi / slices * j)*radius, z0  );
		glVertex3d(cos(TwoPi / slices * j)*radius, sin(TwoPi / slices * j)*radius, z1  );
	    }
	glEnd();

	z0 = z1; z1 += zStep;
    }

}

void solidCone(double base, double height, int slices, int stacks)
{
    int i,j;
    double z0,z1;
    double r0,r1;
    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );
    const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 );
    const double cosn = ( height / sqrt ( height * height + base * base ));
    const double sinn = ( base   / sqrt ( height * height + base * base ));

    z0 = 0.0;
    z1 = zStep;

    r0 = base;
    r1 = r0 - rStep;

    glBegin(GL_TRIANGLE_FAN);

	glNormal3d(0.0,0.0,-1.0);
	glVertex3d(0.0,0.0, z0 );

	for (j=0; j<=slices; j++)
	    glVertex3d(cos(TwoPi / slices * j)*r0, sin(TwoPi / slices * j)*r0, z0);

    glEnd();

    for( i=0; i<stacks-1; i++ )
    {
	glBegin(GL_QUAD_STRIP);

	    for(j=0; j<=slices; j++)
	    {
		glNormal3d(cos(TwoPi / slices * j)*sinn, sin(TwoPi / slices * j)*sinn, cosn);
		glVertex3d(cos(TwoPi / slices * j)*r0,   sin(TwoPi / slices * j)*r0,   z0  );
		glVertex3d(cos(TwoPi / slices * j)*r1,   sin(TwoPi / slices * j)*r1,   z1  );
	    }

	    z0 = z1; z1 += zStep;
	    r0 = r1; r1 -= rStep;

	glEnd();
    }

    glBegin(GL_TRIANGLES);

	glNormal3d(cos(0.0)*sinn, sin(0.0)*sinn, cosn);

	for (j=0; j<slices; j++)
	{
	    glVertex3d(cos(TwoPi / slices * j)*r0,   sin(TwoPi / slices * j)*r0,   z0    );
	    glVertex3d(0,              0,              height);
	    glNormal3d(cos(TwoPi / slices * (j+1))*sinn, sin(TwoPi / slices * (j+1))*sinn, cosn  );
	    glVertex3d(cos(TwoPi / slices * (j+1))*r0,   sin(TwoPi / slices * (j+1))*r0,   z0    );
	}

    glEnd();
}

